package cn.mw.cmdb.timeplan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.mw.cmdb.exception.WarnTitleException;
import cn.mw.cmdb.mongoMapper.MwTimePlanMapper;
import cn.mw.cmdb.mongoMapper.MwTimePlanRelationModuleMapper;
import cn.mw.cmdb.service.impl.BaseSearchService;
import cn.mw.cmdb.timeplan.entity.ActiveTimeEnum;
import cn.mw.cmdb.timeplan.entity.MwTimePlan;
import cn.mw.cmdb.timeplan.entity.MwTimePlanRelationModuleDto;
import cn.mw.cmdb.timeplan.param.MwTimePlanParam;
import cn.mw.cmdb.timeplan.service.MwTimePlanService;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.microMonitorCommon.api.powerjob.PowerJobService;
import cn.mw.microMonitorCommon.entity.cmdb.TimePlanExecutionInfo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class MwTimePlanServiceImpl extends BaseSearchService<MwTimePlan> implements MwTimePlanService, InitializingBean {

    private MwTimePlanMapper mwTimePlanMapper;

    private Map<String ,String> activeTypeMap;

    private MessageSource messageSource;

    private MwTimePlanRelationModuleMapper planRelationModuleMapper;

    @DubboReference(check = false,timeout = 12000)
    private PowerJobService powerJobService;

    public MwTimePlanServiceImpl(MwTimePlanMapper mwTimePlanMapper ,MessageSource messageSource,MwTimePlanRelationModuleMapper planRelationModuleMapper){
        this.mwTimePlanMapper = mwTimePlanMapper;
        this.messageSource = messageSource;
        this.planRelationModuleMapper = planRelationModuleMapper;
    }

    @Override
    public MwTimePlanParam save(MwTimePlanParam param) throws Exception {
        //名称校验
        Query query = new Query();
        query.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlan::getName)).is(param.getName()));
        if(!StringUtils.isEmpty(param.getId())){
            query.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlan::getId)).ne(param.getId()));
        }
        long count = mwTimePlanMapper.count(query);
        if(count > 0){
            throw new WarnTitleException("time-plan-name-check");
        }
        MwTimePlan mwTimePlan = new MwTimePlan();
        BeanUtil.copyProperties(param ,mwTimePlan);
        if(null != param.getCustomTime()){
            mwTimePlan.setActiveSince(param.readActiveSince());
            mwTimePlan.setActiveTill(param.readActiveTill());
        }
        mwTimePlan.init();

        if(null != mwTimePlan.getCrons()){
            MwTimePlan result = mwTimePlanMapper.save(mwTimePlan);
            param.setId(result.getId());
            return param;
        }

        return null;
    }

    @Override
    public MwTimePlanParam select(MwTimePlanParam param) {
        MwTimePlan mwTimePlan = mwTimePlanMapper.findById(param.getId());
        BeanUtil.copyProperties(mwTimePlan ,param);
        param.setCustomTime(mwTimePlan.readCustomTime());
        String activeTypeName = activeTypeMap.get(param.getActiveTimeType());
        if(StringUtils.hasText(activeTypeName)){
            param.setActiveTimeTypeName(activeTypeName);
        }
        return param;
    }

    @Override
    public List<MwTimePlanParam> list(SearchParam param) throws Exception{
        Criteria criteria = genCriteria(param);
        List<MwTimePlan> mwTimePlans = CMDBTool.selectPageList(mwTimePlanMapper ,criteria ,param);
        if(null != mwTimePlans){
            List<MwTimePlanParam> ret = new ArrayList<>();
            for(MwTimePlan mwTimePlan: mwTimePlans){
                MwTimePlanParam item = new MwTimePlanParam();
                BeanUtil.copyProperties(mwTimePlan ,item);
                item.setCustomTime(mwTimePlan.readCustomTime());

                String activeTypeName = activeTypeMap.get(item.getActiveTimeType());
                if(StringUtils.hasText(activeTypeName)){
                    item.setActiveTimeTypeName(activeTypeName);
                }
                ret.add(item);
            }
            return ret;

        }
        return null;
    }

    @Override
    public void delete(MwTimePlanParam timePlanParam) throws Exception {
        timePlanParam.convert();
        Criteria criteria = genCriteria(timePlanParam);
        //查询关联信息
        List<MwTimePlanRelationModuleDto> moduleDtos = CMDBTool.selectAuthorizedList(MwTimePlanRelationModuleDto.class, planRelationModuleMapper, criteria, timePlanParam);
        Query query = new Query();
        query.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlan::getId)).in(timePlanParam.getIds()));
        if(CollectionUtils.isEmpty(moduleDtos)){
            //直接删除数据
            mwTimePlanMapper.remove(query);
            return;
        }
        List<Long> taskIds = moduleDtos.stream().map(s -> s.getTaskId()).collect(Collectors.toList());
        powerJobService.deleteJob(taskIds);
        Query moduleQuery = new Query();
        moduleQuery.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlanRelationModuleDto::getTimePlanId)).in(timePlanParam.getIds()));
        planRelationModuleMapper.remove(moduleQuery);
        mwTimePlanMapper.remove(query);
    }

    @Override
    public List<MwTimePlanRelationModuleDto> getTimePlanDetailInfo(MwTimePlanParam timePlanParam) throws Exception {
        timePlanParam.convert();
        timePlanParam.setSearchClass(MwTimePlanRelationModuleDto.class);
        Criteria criteria = genCriteria(timePlanParam);
        //忽略权限查询
        timePlanParam.setIgnoreDataAuth(true);
        List<MwTimePlanRelationModuleDto> moduleDtos = CMDBTool.selectAuthorizedList(MwTimePlanRelationModuleDto.class, planRelationModuleMapper, criteria, timePlanParam);
        if(CollectionUtils.isEmpty(moduleDtos)){
            return moduleDtos;
        }
        List<String> timePlanIds = moduleDtos.stream().map(s -> s.getTimePlanId()).collect(Collectors.toList());
        Query query = new Query();
        query.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlan::getId)).in(timePlanIds));
        List<MwTimePlan> timePlans = mwTimePlanMapper.find(query);
        //名称设置
        setTimePlanName(timePlans,moduleDtos);
        //根据任务ID查询任务执行情况
        List<Long> taskIds = moduleDtos.stream().map(s -> s.getTaskId()).collect(Collectors.toList());
        List<TimePlanExecutionInfo> executionInfos = powerJobService.getTaskDetail(taskIds);
        if(CollectionUtils.isEmpty(executionInfos)){
            return moduleDtos;
        }
        Map<Long, TimePlanExecutionInfo> taskMap = executionInfos.stream().collect(Collectors.toMap(s -> s.getJobId(), s -> s, (o1, o2) -> o1));
        for (MwTimePlanRelationModuleDto moduleDto : moduleDtos) {
            TimePlanExecutionInfo executionInfo = taskMap.get(moduleDto.getTaskId());
            if(executionInfo == null){continue;}
            moduleDto.setTaskStartTime(executionInfo.getTaskStartTime());
            moduleDto.setTaskEndTime(executionInfo.getTaskEndTime());
            moduleDto.setTimeConsuming(executionInfo.getTimeConsuming());
        }
        return moduleDtos;
    }

    @Override
    public List<MwTimePlan> selectListByIds(MwTimePlanParam timePlanParam) {
        Query query = new Query();
        query.addCriteria(new Criteria(CMDBTool.getFieldName(MwTimePlan::getId)).in(timePlanParam.getIds()));
        return mwTimePlanMapper.find(query);
    }

    @Override
    protected MwTimePlan genObject() {
        return new MwTimePlan();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        activeTypeMap = new HashMap();
        for(ActiveTimeEnum activeTimeEnum :ActiveTimeEnum.values()){
            String value = activeTimeEnum.getLabel(messageSource ,activeTimeEnum.name().toString());
            activeTypeMap.put(activeTimeEnum.name().toString() ,value);
        }
    }

    private void setTimePlanName(List<MwTimePlan> timePlans,List<MwTimePlanRelationModuleDto> moduleDtos){
        Map<String, String> timePlanMap = timePlans.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getName(), (o1, o2) -> o1));
        for (MwTimePlanRelationModuleDto moduleDto : moduleDtos) {
            String timePlanName = timePlanMap.get(moduleDto.getTimePlanId());
            moduleDto.setTimePlanName(timePlanName);
        }
    }

}
